home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / compresn / hv11 / src / dither.c next >
Encoding:
C/C++ Source or Header  |  1992-07-05  |  6.9 KB  |  241 lines

  1. /*
  2.     NAME
  3.        dither - routines to do Floyd-Steinberg dithering
  4.  
  5.    DESCRIPTION
  6.       The assumption is that you have input values in the range
  7.       minIn..maxIn that you want to reduce to the range
  8.       minOut..maxOut.  (For color images, you would dither each color
  9.       component separately.)
  10.  
  11.        Dither a serpentine version of Floyd-Steinberg dithering.  The
  12.       skeleton code to use these routines is:
  13.  
  14.           DitherInit();
  15.          onOddRow = FALSE;
  16.          for (each row) {
  17.              Dither(row, onOddRow);
  18.             onOddRow = !onOddRow;
  19.          }
  20.          DitherTerm();
  21. */
  22.  
  23. #include "jinclude.h"
  24. #include "jmemsys.h"
  25. #include "viewer.h"
  26. #include "hicolor.h"
  27. #include "dither.h"
  28.  
  29.  
  30. #define DInflateBase 15
  31.  
  32. extern BYTE ColorLUT256[];
  33. /*
  34.     NAME
  35.        Dither - apply Floyd-Steinberg dithering to one row
  36.  
  37.    DESCRIPTION
  38.        Adapted from the JPEG source code.
  39.  
  40.       Note that it is acceptable to have pIn == pOut, i.e., to do the
  41.       dithering in place.
  42. */
  43.  
  44. void 
  45. Dither (
  46.      DCtrlType * pCtrl,    /* structure with control parameters */
  47.      int *pIn,      /* input values */
  48.      int *pOut,     /* output values */
  49.      int onOddRow        /* TRUE => current row is odd-numbered */
  50. )
  51. {
  52.   int col;            /* column counter */
  53.   int dir;            /* direction flag */
  54.   int error;            /* value of current error */
  55.   int *nextRowErr;        /* pointer to error buffer for next row */
  56.   int *thisRowErr;        /* pointer to error buffer for this row */
  57.   ulong scale = pCtrl->scale;
  58.   ulong invscale = pCtrl->invscale;
  59.   int val;            /* holds dithered value */
  60.   int width = pCtrl->numCols;
  61.  
  62.   if (onOddRow)
  63.     {                /* work right to left in this row */
  64.       pIn += width - 1;
  65.       pOut += width - 1;
  66.       dir = -1;
  67.       thisRowErr = pCtrl->oddRowErrs + 1;
  68.       nextRowErr = pCtrl->evenRowErrs + width;
  69.     }
  70.   else
  71.     {                /* work left to right in this row */
  72.       dir = 1;
  73.       thisRowErr = pCtrl->evenRowErrs + 1;
  74.       nextRowErr = pCtrl->oddRowErrs + width;
  75.     }
  76.   nextRowErr[0] = 0;        /* need only initialize this one entry */
  77.   for (col = width; col > 0; col--)
  78.     {
  79.  
  80.       /* get current value and adjust for accumulated error */
  81.       val = ((*pIn) << 4) + thisRowErr[0];    /* errors are in units of 1/16 */
  82.       if (val < 0)
  83.     val = 0;
  84.       else
  85.     {
  86.       val += 8;        /* for rounding */
  87.       val >>= 4;
  88.       if (val > pCtrl->maxIn)
  89.         val = pCtrl->maxIn;
  90.     }
  91.  
  92.       /* reduce input value to dithered value */
  93.       *pOut = (int) (pCtrl->minOut +
  94.              ((scale * (val - pCtrl->minIn) + (1L << (DInflateBase - 1))) >> DInflateBase));
  95.  
  96.       /* calculate error (in units of 1/16 value) in dithered value */
  97.       error = -(int) (pCtrl->minIn + (((*pOut - pCtrl->minOut) * invscale
  98.               + (1L << (DInflateBase - 1))) >> DInflateBase) - val);
  99.  
  100.       /* store the error */
  101.       val = 2 * error;
  102.       nextRowErr[-1] = error;    /* not +=, since not initialized yet */
  103.       error += val;        /* form error * 3 */
  104.       nextRowErr[1] += error;
  105.       error += val;        /* form error * 5 */
  106.       nextRowErr[0] += error;
  107.       error += val;        /* form error * 7 */
  108.       thisRowErr[1] += error;
  109.       pIn += dir;
  110.       pOut += dir;
  111.       thisRowErr += 1;
  112.       nextRowErr -= 1;
  113.     }
  114. }
  115.  
  116. void 
  117. DitherChar (
  118.      DCtrlType * pCtrl,    /* structure with control parameters */
  119.      JSAMPLE *pIn,      /* input values */
  120.      JSAMPLE *pOut,     /* output values */
  121.      int onOddRow        /* TRUE => current row is odd-numbered */
  122. )
  123. {
  124.   int col;            /* column counter */
  125.   int dir;            /* direction flag */
  126.   int error;            /* value of current error */
  127.   int *nextRowErr;        /* pointer to error buffer for next row */
  128.   int *thisRowErr;        /* pointer to error buffer for this row */
  129.   ulong scale = pCtrl->scale;
  130.   ulong invscale = pCtrl->invscale;
  131.   int val;            /* holds dithered value */
  132.   int width = pCtrl->numCols;
  133.  
  134.   if (onOddRow)
  135.     {                /* work right to left in this row */
  136.       pIn += width - 1;
  137.       pOut += width - 1;
  138.       dir = -1;
  139.       thisRowErr = pCtrl->oddRowErrs + 1;
  140.       nextRowErr = pCtrl->evenRowErrs + width;
  141.     }
  142.   else
  143.     {                /* work left to right in this row */
  144.       dir = 1;
  145.       thisRowErr = pCtrl->evenRowErrs + 1;
  146.       nextRowErr = pCtrl->oddRowErrs + width;
  147.     }
  148.   nextRowErr[0] = 0;        /* need only initialize this one entry */
  149.   for (col = width; col > 0; col--)
  150.     {
  151.  
  152.       /* get current value and adjust for accumulated error */
  153.       val = ((ColorLUT256[GETJSAMPLE(*pIn)]) << 4) + thisRowErr[0];    /* errors are in units of 1/16 */
  154.       if (val < 0)
  155.     val = 0;
  156.       else
  157.     {
  158.       val += 8;        /* for rounding */
  159.       val >>= 4;
  160.       if (val > pCtrl->maxIn)
  161.         val = pCtrl->maxIn;
  162.     }
  163.  
  164.       /* reduce input value to dithered value */
  165.       *pOut = (JSAMPLE) (pCtrl->minOut +
  166.              ((scale * (val - pCtrl->minIn) + (1L << (DInflateBase - 1))) >> DInflateBase));
  167.  
  168.       /* calculate error (in units of 1/16 value) in dithered value */
  169.       error = -(int) (pCtrl->minIn + (((*pOut - pCtrl->minOut) * invscale
  170.               + (1L << (DInflateBase - 1))) >> DInflateBase) - val);
  171.  
  172.       /* store the error */
  173.       val = 2 * error;
  174.       nextRowErr[-1] = error;    /* not +=, since not initialized yet */
  175.       error += val;        /* form error * 3 */
  176.       nextRowErr[1] += error;
  177.       error += val;        /* form error * 5 */
  178.       nextRowErr[0] += error;
  179.       error += val;        /* form error * 7 */
  180.       thisRowErr[1] += error;
  181.       pIn += dir;
  182.       pOut += dir;
  183.       thisRowErr += 1;
  184.       nextRowErr -= 1;
  185.     }
  186. }
  187.  
  188. /*
  189.     NAME
  190.        DitherInit - initialize dither buffers and control parameters
  191.  
  192.    RETURN VALUES
  193.        0        if all OK
  194.       1        on error (probably insufficient memory)
  195. */
  196.  
  197. int 
  198. DitherInit (
  199.          BYTE minIn,    /* minimum input value */
  200.          BYTE maxIn,    /* maximum input value */
  201.          BYTE minOut,    /* minimum output value */
  202.          BYTE maxOut,    /* maximum output value */
  203.          int numCols,    /* number of columns in each row */
  204.          DCtrlType * pCtrl    /* structure with control parameters */
  205. )
  206. {
  207.   pCtrl->minIn = minIn;
  208.   pCtrl->maxIn = maxIn;
  209.   pCtrl->minOut = minOut;
  210.   pCtrl->maxOut = maxOut;
  211.   pCtrl->numCols = numCols;
  212.   pCtrl->scale = ((maxOut - minOut) << DInflateBase) / (maxIn - minIn);
  213.   pCtrl->invscale = ((maxIn - minIn) << DInflateBase) / (maxOut - minOut);
  214.   pCtrl->oddRowErrs = (int *) jget_small ((numCols + 2) * sizeof (int));
  215.   if (pCtrl->oddRowErrs == NULL)
  216.     return 1;
  217.   memset (pCtrl->oddRowErrs, 0, (numCols + 2) * sizeof (int));
  218.   pCtrl->evenRowErrs = (int *) jget_small ((numCols + 2) * sizeof (int));
  219.   if (pCtrl->evenRowErrs == NULL)
  220.     return 1;
  221.   memset (pCtrl->evenRowErrs, 0, (numCols + 2) * sizeof (int));
  222.   return 0;
  223. }
  224.  
  225. /*
  226.     NAME
  227.        DitherTerm - clean up after dither operation
  228.  
  229.    DESCRIPTION
  230.        Frees up memory used for error buffers.
  231. */
  232.  
  233. void 
  234. DitherTerm (
  235.          DCtrlType * pCtrl    /* structure with control parameters */
  236. )
  237. {
  238.   jfree_small (pCtrl->oddRowErrs);
  239.   jfree_small (pCtrl->evenRowErrs);
  240. }
  241.